<!-- 表格组件 -->
<!-- 支持：el-table 全部属性、事件、插槽，同官方文档写法 -->
<!-- 扩展功能：分页组件、渲染自定义列、loading、表格全局边框、斑马纹、表格尺寸、表头背景配置 -->
<!-- 获取 ref：默认暴露了 elTableRef 外部通过 ref.value.elTableRef 可以调用 el-table 方法 -->
<template>
  <!-- ...$attrs -->
  <div class="art-table" :class="{ 'is-empty': isEmpty }" :style="containerHeight">
    <ElTable ref="elTableRef" v-loading="!!loading"
      v-bind="{ ...props, height, stripe, border, size, headerCellStyle }">
      <template v-for="col in columns" :key="col.prop || col.type">
        <!-- 渲染全局序号列 -->
        <ElTableColumn v-if="col.type === 'globalIndex'" v-bind="{ ...col }">
          <template #default="{ $index }">
            <span>{{ getGlobalIndex($index) }}</span>
          </template>
        </ElTableColumn>

        <!-- 渲染展开行 -->
        <ElTableColumn v-else-if="col.type === 'expand'" v-bind="cleanColumnProps(col)">
          <template #default="{ row }">
            <component :is="col.formatter ? col.formatter(row) : null" />
          </template>
        </ElTableColumn>

        <!-- 渲染普通列 -->
        <ElTableColumn v-else v-bind="cleanColumnProps(col)">
          <template v-if="col.useHeaderSlot && col.prop" #header="headerScope">
            <slot :name="col.headerSlotName || `${col.prop}-header`"
              v-bind="{ ...headerScope, prop: col.prop, label: col.label }">
              {{ col.label }}
            </slot>
          </template>
          <template v-if="col.useSlot && col.prop" #default="slotScope">
            <slot :name="col.slotName || col.prop" v-bind="{
              ...slotScope,
              prop: col.prop,
              value: col.prop ? slotScope.row[col.prop] : undefined
            }" />
          </template>
        </ElTableColumn>
      </template>

      <template v-if="$slots.default" #default>
        <slot />
      </template>

      <template #empty>
        <div v-if="loading"></div>
        <ElEmpty v-else :description="emptyText" :image-size="120" />
      </template>
    </ElTable>

    <div class="pagination custom-pagination" v-if="showPagination" :class="mergedPaginationOptions?.align"
      ref="paginationRef">
      <ElPagination v-bind="mergedPaginationOptions" :total="pagination?.total" :disabled="loading"
        :page-size="pagination?.size" :current-page="pagination?.current" @size-change="handleSizeChange"
        @current-change="handleCurrentChange" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted, onUnmounted, watch } from 'vue'
import type { ElTable, TableProps } from 'element-plus'
import { storeToRefs } from 'pinia'
import { ColumnOption } from '@/types'
import { useTableStore } from '@/store/modules/table'
import { useCommon } from '@/composables/useCommon'
import { useElementSize, useWindowSize } from '@vueuse/core'

defineOptions({ name: 'ArtTable' })

const { width } = useWindowSize()
const elTableRef = ref<InstanceType<typeof ElTable> | null>(null)
const paginationRef = ref<HTMLElement>()
const tableStore = useTableStore()
const { isBorder, isZebra, tableSize, isFullScreen, isHeaderBackground } = storeToRefs(tableStore)

// 动态计算表格头部高度
const tableHeaderHeight = ref(0)

// ResizeObserver 用于监听表格头部高度变化
let resizeObserver: ResizeObserver | null = null

/** 分页配置接口 */
interface PaginationConfig {
  /** 当前页码 */
  current: number
  /** 每页显示条目个数 */
  size: number
  /** 总条目数 */
  total: number
}

/** 分页器配置选项接口 */
interface PaginationOptions {
  /** 每页显示个数选择器的选项列表 */
  pageSizes?: number[]
  /** 分页器的对齐方式 */
  align?: 'left' | 'center' | 'right'
  /** 分页器的布局 */
  layout?: string
  /** 是否显示分页器背景 */
  background?: boolean
  /** 只有一页时是否隐藏分页器 */
  hideOnSinglePage?: boolean
  /** 分页器的大小 */
  size?: 'small' | 'default' | 'large'
  /** 分页器的页码数量 */
  pagerCount?: number
}

/** ArtTable 组件的 Props 接口 */
interface ArtTableProps extends TableProps<Record<string, any>> {
  /** 加载状态 */
  loading?: boolean
  /** 列渲染配置 */
  columns?: ColumnOption[]
  /** 分页状态 */
  pagination?: PaginationConfig
  /** 分页配置 */
  paginationOptions?: PaginationOptions
  /** 空数据表格高度 */
  emptyHeight?: string
  /** 空数据时显示的文本 */
  emptyText?: string
  /** 是否开启 ArtTableHeader，解决表格高度自适应问题 */
  showTableHeader?: boolean
}

const props = withDefaults(defineProps<ArtTableProps>(), {
  columns: () => [],
  fit: true,
  showHeader: true,
  stripe: undefined,
  border: undefined,
  size: undefined,
  emptyHeight: '100%',
  emptyText: '暂无数据',
  showTableHeader: true
})

const LAYOUT = {
  MOBILE: 'prev, pager, next, sizes, jumper, total',
  IPAD: 'prev, pager, next, jumper, total',
  DESKTOP: 'total, prev, pager, next, sizes, jumper'
}

const layout = computed(() => {
  if (width.value < 768) {
    return LAYOUT.MOBILE
  } else if (width.value < 1024) {
    return LAYOUT.IPAD
  } else {
    return LAYOUT.DESKTOP
  }
})

// 默认分页常量
const DEFAULT_PAGINATION_OPTIONS: PaginationOptions = {
  pageSizes: [10, 20, 30, 50, 100],
  align: 'center',
  background: true,
  layout: layout.value,
  hideOnSinglePage: false,
  size: 'default',
  pagerCount: width.value > 1200 ? 7 : 5
}

// 合并分页配置
const mergedPaginationOptions = computed(() => ({
  ...DEFAULT_PAGINATION_OPTIONS,
  ...props.paginationOptions
}))

// 边框 (优先级：props > store)
const border = computed(() => props.border ?? isBorder.value)
// 斑马纹
const stripe = computed(() => props.stripe ?? isZebra.value)
// 表格尺寸
const size = computed(() => props.size ?? tableSize.value)
// 数据是否为空
const isEmpty = computed(() => props.data?.length === 0)

const { height: paginationHeight } = useElementSize(paginationRef)

// 容器高度计算
const containerHeight = computed(() => {
  let offset = 0
  if (!props.showTableHeader) {
    // 没有表格头部时，只考虑分页器高度
    offset = paginationHeight.value === 0 ? 0 : paginationHeight.value + PAGINATION_SPACING.value
  } else {
    // 有表格头部时，动态计算表格头部高度 + 分页器高度 + 间距
    const headerHeight = tableHeaderHeight.value || DEFAULT_TABLE_HEADER_HEIGHT
    const paginationOffset =
      paginationHeight.value === 0 ? 0 : paginationHeight.value + PAGINATION_SPACING.value
    offset = headerHeight + paginationOffset + TABLE_HEADER_SPACING
  }
  return { height: offset === 0 ? '100%' : `calc(100% - ${offset}px)` }
})

// 表格高度逻辑
const height = computed(() => {
  // 全屏模式下占满全屏
  if (isFullScreen.value) return '100%'
  // 空数据且非加载状态时固定高度
  if (isEmpty.value && !props.loading) return props.emptyHeight
  // 使用传入的高度
  if (props.height) return props.height
  // 默认占满容器高度
  return '100%'
})

// 表头背景颜色样式
const headerCellStyle = computed(() => ({
  background: isHeaderBackground.value
    ? 'var(--el-fill-color-lighter)'
    : 'var(--art-main-bg-color)',
  ...(props.headerCellStyle || {}) // 合并用户传入的样式
}))

// 是否显示分页器
const showPagination = computed(() => props.pagination && !isEmpty.value)

// 清理列属性，移除插槽相关的自定义属性，确保它们不会被 ElTableColumn 错误解释
const cleanColumnProps = (col: ColumnOption) => {
  const columnProps = { ...col }
  // 删除自定义的插槽控制属性
  delete columnProps.useHeaderSlot
  delete columnProps.headerSlotName
  delete columnProps.useSlot
  delete columnProps.slotName
  return columnProps
}

// 分页大小变化
const handleSizeChange = (val: number) => {
  emit('pagination:size-change', val)
}

// 分页当前页变化
const handleCurrentChange = (val: number) => {
  emit('pagination:current-change', val)
  scrollToTop() // 页码改变后滚动到表格顶部
}

// 滚动表格内容到顶部，并可以联动页面滚动到顶部
const scrollToTop = () => {
  nextTick(() => {
    elTableRef.value?.setScrollTop(0) // 滚动 ElTable 内部滚动条到顶部
    useCommon().scrollToTop() // 调用公共 composable 滚动页面到顶部
  })
}

// 全局序号
const getGlobalIndex = (index: number) => {
  if (!props.pagination) return index + 1
  const { current, size } = props.pagination
  return (current - 1) * size + index + 1
}

const emit = defineEmits<{
  (e: 'pagination:size-change', val: number): void
  (e: 'pagination:current-change', val: number): void
}>()

// 表格头部默认高度常量
const DEFAULT_TABLE_HEADER_HEIGHT = 44
// 分页器与表格之间的间距常量（计算属性，响应 showTableHeader 变化）
const PAGINATION_SPACING = computed(() => (props.showTableHeader ? 6 : 15))
// 表格头部与表格之间的间距常量
const TABLE_HEADER_SPACING = 12

// 查找并监听表格头部高度变化
const observeTableHeader = () => {
  try {
    // 清理之前的监听
    if (resizeObserver) {
      resizeObserver.disconnect()
      resizeObserver = null
    }

    // 如果不需要显示表格头部，直接返回
    if (!props.showTableHeader) {
      tableHeaderHeight.value = 0
      return
    }

    // 查找表格头部元素
    const tableHeader = document.getElementById('art-table-header') as HTMLElement
    if (!tableHeader) {
      // 如果找不到表格头部，使用默认高度
      tableHeaderHeight.value = DEFAULT_TABLE_HEADER_HEIGHT
      return
    }

    // 初始化高度
    tableHeaderHeight.value = tableHeader.offsetHeight

    // 创建 ResizeObserver 监听高度变化
    resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) {
        if (entry.target === tableHeader) {
          tableHeaderHeight.value = entry.contentRect.height
        }
      }
    })

    resizeObserver.observe(tableHeader)
  } catch (error) {
    console.warn('监听表格头部高度失败:', error)
    // 出错时使用默认高度
    tableHeaderHeight.value = DEFAULT_TABLE_HEADER_HEIGHT
  }
}

// 组件挂载后查找表格头部
onMounted(() => {
  nextTick(() => {
    observeTableHeader()
  })
})

// 监听数据变化和表格头部显示状态变化，重新观察表格头部
watch(
  [() => props.data, () => props.showTableHeader],
  () => {
    nextTick(() => {
      observeTableHeader()
    })
  },
  { flush: 'post' }
)

// 组件卸载时清理 ResizeObserver
onUnmounted(() => {
  if (resizeObserver) {
    resizeObserver.disconnect()
    resizeObserver = null
  }
})

defineExpose({
  scrollToTop,
  elTableRef
})
</script>

<style lang="scss" scoped>
@use './style';
</style>
